#include "slab.h"

namespace kvalloc {
    
bool SlabMeta::Alloc(FileAddr & addr) {
    int alloc_idx;
    if(!bitmap_.blindset(alloc_idx) || alloc_idx >= (SLAB_SIZE / size_class_)) {
        return false;
    } else {
        addr.slabid = slabid_;
        addr.slaboff = alloc_idx * size_class_;
        count_.fetch_add(1);
        return true;
    }
}

void SlabMeta::Free(FileAddr addr) {
    bitmap_.reset(addr.slaboff / size_class_);
    count_.fetch_sub(1);
}


SlabMeta * SlabList::PopFront(SlabMeta * slab_pool) { // append to the left
    if(head_ == tail_ && head_ != 0) { // only one left
        uint64_t old = head_;
        head_ = tail_ = 0;
        return &slab_pool[old];
    } else {
        uint64_t old = head_;
        head_ = slab_pool[head_].next;
        return &slab_pool[old];
    }
}

void SlabList::PushBack(SlabMeta * slab_pool, uint64_t slabid) { // append to the left
    if(head_ == 0) {
        head_ = tail_ = slabid;
    } else {
        slab_pool[tail_].next = slabid;
        tail_ = slabid;
        slab_pool[slabid].next = 0;
    }
}

void SlabList::Append(SlabMeta * slab_pool, SlabList & other) {
    if(head_ == 0) {
        head_ = other.head_;
        tail_ = other.tail_;
    } else {
        slab_pool[tail_].next = other.head_;
        if(other.head_ != 0) tail_ = other.tail_;
    }
}

} // namespace kvalloc